function towerdefense()
{
	var gr;
	var towers;
	var enemys;
	var pause;
	var levelGraphic;
	var gPanel;
	var path;
	var levels;
	var levelIndex;
	var dedEnemys;
	var enemyCount;
	var towerTypes;
	var enemyTypes;
	var towerBeingCreated;
	var towerBeingCreatedType;
	var mouseX;
	var mouseY;
	var points;
	var lifes;
	var selectedTower;
	var levelObjectTypes = new Array();

	this.levels = new Array();
	this.levelIndex = -1;
	this.enemyCount = 0;
}

towerdefense.prototype.Init = function()
{
	this.pause = false;

	//inicializo el motor grafico
	this.gr = new jsvgGraphic();
	this.gr.Init();

	//dibujo el fondo
	this.levelGraphic = new MovieClip();
	this.levelGraphic.DrawRectangle(0, 0, 800, 600, "#dfcb8f", 1);
	this.levelGraphic._root.addEventListener("mousemove", Delegate.create(this, this.onMouseMove), false);
	this.LoadObjectTypes();
	
	this.LoadTowerTypes();
	this.LoadEnemyTypes();
	this.LoadLevels();
	
	this.points = 60;
	this.lifes = 20;

	//creo el panel
	this.gPanel = new GamePanel(650, 150, this);
	this.gPanel.Init();
	
	//inicializo el path
	this.path = new Array();

	//creo los enemigos
	this.enemys = new Array();
	this.dedEnemys = new Array();

	//creo las torres
	this.towers = new Array();
	this.CreateTower(250, 150, this.towerTypes[0]);
	this.CreateTower(350, 450, this.towerTypes[1]);

	//this.InitNextLevel();
	
	//comienzo la animación
	setInterval("td.Animate()", 30);
}

towerdefense.prototype.CreateTower = function(x, y, ttype)
{
	var t = new Tower(this.towers.length, ttype);
	this.towers.push(t);
	t.Init(x, y, 0, this);
	
	t._root._root.addEventListener("mouseup", Delegate.create(this, this.onTowerTypeClick, t), false);
}

towerdefense.prototype.CreateEnemy = function(type, x, y)
{
	e = new Enemy(this, this.enemyCount);
	this.enemys.push(e);
	e.Init(this, x, y, this.enemyTypes[type]);
	
	e._root._root.addEventListener("mouseup", Delegate.create(this, this.onEnemyClick, e), false);

	log("creo enemigos: " + this.enemys);

	this.enemyCount++;
}

towerdefense.prototype.Animate = function()
{
	if(!this.pause)
	{
		//creo enemigos
		if (this.levelIndex >= 0)
		{
			et = this.levels[this.levelIndex].GetNextEnemy();
			if(et != null) this.CreateEnemy(et, this.path[0].x, this.path[0].y);
		}

		//Animo los enemigos y las torres
		if(this.enemys.length > 0)
		{
			for(var i = 0; i < this.enemys.length; i++)
				this.enemys[i].Work();
		}
		
		for(var i = 0; i < this.towers.length; i++)
			this.towers[i].Work();
		
		//Elimino los enemigos muertos
		if(this.enemys.length > 0)
			this.EraseDedEnemys();
		
		//Animo el panel
		this.gPanel.Work();
	}
}

towerdefense.prototype.EnemyDied = function(enemy, reachedEnd)
{
	for(var i = 0; i < this.enemys.length; i++)
	{
		//solo si el enemigo muerto figura en la lista
		//de enemigos lo agrego como muerto
		if(this.enemys[i] == enemy)
		{
				var exists = false;
				
				for(var j = 0; j < this.dedEnemys.length; j++)
				{
					if (this.dedEnemys[j] == enemy) 
					{
						exists = true;
						break;
					}
				}
				
				if (!exists) 
				{
					this.dedEnemys.push(enemy);
					if(!reachedEnd)
					{
						this.points += Math.floor(enemy._type.energy / 100);
						this.gPanel.SetPoints(this.points);
					}
				}
				
				break;
		}
	}
}  

towerdefense.prototype.EraseDedEnemys = function()
{
	var checkEnd = this.dedEnemys.length > 0;

	for(var i = 0; i < this.dedEnemys.length; i++)
	{
		for(var j = 0; j < this.enemys.length; j++)
		{
			if(this.dedEnemys[i] == this.enemys[j])
			{
				log("enemigo muerto: " + this.enemys[i]);
				
				this.dedEnemys[i]._root.Dispose();
				this.dedEnemys.splice(i, 1);
				this.enemys.splice(j, 1);
				log("enemigos: " + this.enemys);
				break;
			}
		}
	}

	if(checkEnd) this.CheckLevelEnd();
}

towerdefense.prototype.CheckLevelEnd = function()
{
	log("CheckLevelEnd - enemysLeft: " + this.levels[this.levelIndex].enemysLeft);
	if(this.levels[this.levelIndex].enemysLeft == 0 && this.enemys.length == 0)
	this.InitNextLevel();
}

towerdefense.prototype.InitNextLevel = function()
{
	if(this.levels.length > this.levelIndex + 1)
	{
		this.levelIndex++;
		log("----- Next level " + (this.levelIndex + 1) + " -----");
		
		this.path = this.levels[this.levelIndex].path;
		this.DrawEnemyPath();
		
		this.enemyCount = 0;
		this.dedEnemys = new Array();
	}
	else log("----- End game -----");
}

towerdefense.prototype.LoadLevels = function()
{
	for(var i = 0; i < 4; i++)
	{
		var l = new Level(i);
		l.enemys = new Array();
		for(var j = 0; j < 7; j++)
			l.enemys.push({"time" : 3000, "type" : i});
		
		l.path = new Array();
		l.path.push({"x" : 0,   "y" : 20});
		l.path.push({"x" : 220, "y" : 20});
		l.path.push({"x" : 220, "y" : 420});
		l.path.push({"x" : 340, "y" : 420});
		l.path.push({"x" : 340, "y" : 20});
		l.path.push({"x" : 540, "y" : 20});
		l.path.push({"x" : 540, "y" : 540});
		l.path.push({"x" : 0,   "y" : 540});
		
		this.levels.push(l);
	}
}

towerdefense.prototype.LoadTowerTypes = function()
{
	this.towerTypes = new Array();

	for(var i = 0; i < 3; i++)
	{
		tt = new TowerType();
		tt.resourceName = "T" + (i + 1);
		tt.damage = 5 * i;
		tt.damageArea = 200;
		tt.maxMisiles = 1;
		tt.cost = 10 + (10 * i);
		tt.coolDown = 0;
		this.towerTypes.push(tt);
	}
}

towerdefense.prototype.LoadEnemyTypes = function()
{
	this.enemyTypes = new Array();

	for(var i = 0; i < 4; i++)
	{
		et = new EnemyType();
		et.resourceName = "E" + (i + 1);
		et.speed = 2 * (1 + i * 0.1);
		et.energy =  300 + (10 * i)
		this.enemyTypes.push(et);
	}
}

towerdefense.prototype.LoadObjectTypes = function()
{
	this.levelObjectTypes = new Array();
	this.levelObjectTypes.push("Dust0");
	this.levelObjectTypes.push("Dust1");
	this.levelObjectTypes.push("Path0");
	this.levelObjectTypes.push("Path1");
	this.levelObjectTypes.push("Path2");
	this.levelObjectTypes.push("Path3");
	this.levelObjectTypes.push("Path4");
	this.levelObjectTypes.push("Path5");
	this.levelObjectTypes.push("Tree0");
	this.levelObjectTypes.push("Tree1");
	this.levelObjectTypes.push("Tree2");
}

towerdefense.prototype.DrawEnemyPath = function()
{
	var pathSteps = this.path.length;
	var prev_direction = 0;
	for(var i = 0; i < pathSteps - 1; i++)
	{
		var direction = 0;
		var orientation = 0;
		var bloks = 0;
		
		//determino si el segmento es horizontal o vertical
		if(this.path[i].x == this.path[i + 1].x)  //vertical
		{
			orientation = 0;
			var minPosition = Math.min(this.path[i].y, this.path[i + 1].y);
			var maxPosition = Math.max(this.path[i].y, this.path[i + 1].y);
			bloks = Math.floor((maxPosition - minPosition) / 40);
			direction = this.path[i].y < this.path[i+1].y ? 1 : -1;
			for(var j = 1; j < bloks; j ++)
			{
				var p = new MovieClip("path", this.levelGraphic);
				p.LoadResource(this.levelObjectTypes[3]);
				p.x = Math.floor(this.path[i].x / 40) * 40;
				p.y = Math.floor(this.path[i].y / 40) * 40 + j * 40 * direction;
			}
		}
		else if(this.path[i].y == this.path[i + 1].y) //horizontal
		{
			orientation = 1;
			var minPosition = Math.min(this.path[i].x, this.path[i + 1].x);
			var maxPosition = Math.max(this.path[i].x, this.path[i + 1].x);
			bloks = Math.floor((maxPosition - minPosition) / 40);
			direction = this.path[i].x < this.path[i+1].x ? 1 : -1;
			for(var j = 1; j < bloks; j++)
			{
				var p = new MovieClip("path", this.levelGraphic);
				p.LoadResource(this.levelObjectTypes[2]);
				p.x = Math.floor(this.path[i].x / 40) * 40 + j * 40 * direction;
				p.y = Math.floor(this.path[i].y / 40) * 40;
			}
		}
		else
		{
			alert("Path error. One segment is not horizontal or vertical");
			log("Path error. One segment is not horizontal or vertical");
			break;
		}
		
		//dibujo los bloques de las esquinas ╗ ╝ ╚ ╔
		if(i > 0)
		{
			var bloqType = 0;
			if(orientation == 0) //vertical
			{
				if(prev_direction == 1) //derecha
				{
					if(direction == 1) bloqType = 4; //abajo ╗
					else bloqType = 5; //arriba ╝
				}
				else //izquierda
				{
					if(direction == 1) bloqType = 7; //abajo ╔
					else bloqType = 6; //arriba ╚
				}
			}
			else //horizontal
			{
				if(prev_direction == 1) //abajo
				{
					if(direction == 1) bloqType = 6; //derecha ╚
					else bloqType = 5; //izquierda ╝
				}
				else //arriba
				{
					if(direction == 1) bloqType = 7; //derecha ╔
					else bloqType = 4; //izquierda ╗
				}
			}
			
			var p = new MovieClip("path", this.levelGraphic);
			p.LoadResource(this.levelObjectTypes[bloqType]);
			p.x = Math.floor(this.path[i].x / 40) * 40;
			p.y = Math.floor(this.path[i].y / 40) * 40;
		}
		else if(i == 0) //dibujo el primer bloque del primer path
		{
			var p = new MovieClip("path", this.levelGraphic);
			
			if(orientation == 0) //vertical
			{
				p.LoadResource(this.levelObjectTypes[3]);
				p.x = Math.floor(this.path[i].x / 40) * 40;
				p.y = Math.floor(this.path[i].y / 40) * 40;
			}
			else //horizontal
			{
				p.LoadResource(this.levelObjectTypes[2]);
				p.x = Math.floor(this.path[i].x / 40) * 40;
				p.y = Math.floor(this.path[i].y / 40) * 40;
			}
		}
		
		
		if(i == pathSteps - 2) //dibujo el último bloque del último path
		{
			var p = new MovieClip("path", this.levelGraphic);
			
			if(orientation == 0) //vertical
			{
				p.LoadResource(this.levelObjectTypes[3]);
				p.x = Math.floor(this.path[i + 1].x / 40) * 40;
				p.y = Math.floor(this.path[i + 1].y / 40) * 40;
			}
			else //horizontal
			{
				p.LoadResource(this.levelObjectTypes[2]);
				p.x = Math.floor(this.path[i + 1].x / 40) * 40;
				p.y = Math.floor(this.path[i + 1].y / 40) * 40;
			}
		}
		
		prev_direction = direction;
	}
}

towerdefense.prototype.DropNewTower = function(ttype)
{
	if (this.selectedTower != null)
	{
		
	}
	
	if (this.selectedTower != null) this.selectedTower.HideArea();
	this.selectedTower = null;
	
	//borro la torre elegida
	if (this.towerBeingCreated != null) this.towerBeingCreated.Dispose();
	
	//creo la torre temporal
	var t = new MovieClip();
	ttype.Draw(t);
	this.towerBeingCreated = t;
	this.towerBeingCreatedType = ttype;
	
	t._root.addEventListener("mouseup", Delegate.create(this, this.onNewTowerMouseUp), false);
}

towerdefense.prototype.onMouseMove = function(evt)
{
	if (this.towerBeingCreated != null)
	{
		this.towerBeingCreated.x = Math.floor(evt.clientX / 40) * 40;
		this.towerBeingCreated.y = Math.floor(evt.clientY / 40) * 40;
		
		this.mouseX = evt.clientX;
		this.mouseY = evt.clientY;
	}
}

towerdefense.prototype.onNewTowerMouseUp = function(evt)
{
	if (this.towerBeingCreated != null)
	{
		this.towerBeingCreated.Dispose();
		this.towerBeingCreated = null;
		
		if (this.points >= this.towerBeingCreatedType.cost)
		{
			var x = this.mouseX;
			var y = this.mouseY;
			
			//solo la creo si esta dentro de los límites
			if(x > 20 && x < 580 && y > 20 && y < 580)
			{
				log(this.towerBeingCreatedType);
				
				this.CreateTower(Math.floor(x / 40) * 40, 
								 Math.floor(y / 40) * 40, 
								 this.towerBeingCreatedType);
				
				//actualizo los puntos
				this.points -= this.towerBeingCreatedType.cost;
				this.gPanel.SetPoints(this.points);
			}
		}
	}
}

towerdefense.prototype.onTowerTypeClick = function(evt, tower)
{
	if (this.selectedTower != null) this.selectedTower.HideArea();
	this.selectedTower = tower;
	
	this.gPanel.ShowTowerPropertyes(tower);
	tower.ShowArea();
}

towerdefense.prototype.onEnemyClick = function(evt, enemy)
{
	if (this.selectedTower != null) this.selectedTower.HideArea();
	this.selectedTower = null;
	
	this.gPanel.ShowEnemyPropertyes(enemy);
}

towerdefense.prototype.onEnemyReachEnd = function(enemy)
{
	log("onEnemyReachEnd: " + enemy);
	
	this.lifes --;
	this.gPanel.SetLifes(this.lifes);
	
	this.EnemyDied(enemy, true);
	
	if(this.lifes == 0)
	{
		log("----- Game over -----");
	}
}

towerdefense.prototype.Pause = function()
{
	this.pause = !this.pause;
}

towerdefense.prototype.ToString = function()
{
	return "[towerdefense]";
}